/*
Copyright (C) 2014  Johan Degraeve

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/gpl.txt>.

*/

package helpdiabetesj2me;

import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.InvalidRecordIDException;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.RecordStoreNotFoundException;
import javax.microedition.rms.RecordStoreNotOpenException;



class GetItemFromUser extends MyCanvas implements Runnable, CommandListener {

    //creating texts in arrays
    //for now size of arrays is only one, but if languages need to be added, then add additional text in each array
    //and increment index which is defined in HelpDiabetes.java

         static final String[] str_zoek = {"Zoek"};
         static final String[] str_afsl = {"Afsluiten"};
         static final String[] str_afsl_short = {"Exit"};
         static final String[] str_kiezen = {"Kiezen"};
         static final String[] str_lijst = {"Lijst"};
         static final String[] str_tnlijst = {"Toon Lijst"};
         static final String[] str_total = {"Totaal"};
         static final String[] str_totall = {"Toon huidig totaal"};
         static final String[] str_leegm = {"Leegmaken"};
         static final String[] str_leegml = {"Lijst leegmaken"};
         static final String[] str_herl = {"Herladen"};
         static final String[] str_herll = {"Voedingsmiddelenbestand herladen"};
         static final String[] str_settings = {"Instellingen"};
         static final String[] str_info = {"Info/Help"};
         static final String[] str_confirm = {"De lijst met reeds toegevoegde voedingsmiddelen leegmaken ?"};
         static final String[] str_ja = {"Ja"};
         static final String[] str_nee = {"Nee"};
         static final String[] str_lijstleeg = {"De lijst met toegevoegde voedingsmiddelen is al leeg !"};
         static final String[] str_infotext = {"HelpDiabetes laat toe de koolhydraatwaarde te berekenen van een maaltijd."};
         static final String[] str_versie = {"Versie"};
         static final String[] str_beperkt = {""};
         static final String[] str_moreinfo = {"Voor meer info"};
         static final String[] str_deepsrch = {"Zoek meer"};
         static final String[] str_deepsrch_short = {"Zoek meer"};

        //method ItemSelected will be called whenever user has selected an item
        public AddItem additem;


        //method showlist will be used to show the contents of selitemsrs
        ReadItemList ritmlist;

        //points to the last item in the recordstore. Initially set to 0 because foodfile opening/creation hasn't started yet'
        //will get it's definitive value by FinishFoodfileCreation().
        //Value will be actual recordsstoresize, the sum of the sizes of all RecordStores used to store the foodtable.
        public static int foodrssize =0;

        //nr of the firstrecord that is currently shown - can be different from firstrec after user has been using UP and DOWN keys
        int shownrec = 0;

        //used as global variable in run() and searchfirst()
        int newlast = 0;

        //used
        char tmpchr;

        //used in searchfirst and searchlast
        static  byte[] be;
        static int belength;


        // point to firstrecord and lastrecord that will be used by search algorithm after character has been added
        // only used in some methods like keypressed - addcharintext ... to check if notify() will be sent or not
        // notify will only be one if difference between lastrec and firstrec is small enough, otherwise the search algorithm
        // consumes too much time
        int firstrec = 0;
        int lastrec = 0;

        // Commands used
        private Command exit;//used to exit the application
        private Command empty;// to delete HelpDiabetes.selitemsrs
        private Command loadfile;//to load a new foodfile
        private Command showlist;//to list contents of HelpDiabetes.selitemsrs in a new screen
        private Command ja;//used in confirmation of deletion itemlist
        private Command nee;//used in confirmation of deletion itemlist
        private Command settings;//used for changing the settings
        private Command kiezen;//same effect as select button, chose the highlited fooditem
        private Command infopage;//for opening page with information about application
        private Command deepsearch_cmd;//for starting detailed search
        private Command own_element;//for adding element  with name,percentage of carbs, amount

        ChangeSettingsForm changesettingsform;
        static public DeepSearch deepsearch;


        // define the letters on the keys 2 through 9 in a String array
	public static final String[] keys = {"abc", "def", "ghi", "jkl",
	"mno", "pqrs", "tuv", "wxyz"};

        // a timer to measure the time until confirmation of the current key. The timer is stored in keyTimer.
        // The variables keyMajor and keyMinor contain the index in the keys array and the index inside the corresponding string.
        Timer keyTimer;

        int keyMajor = -1;
	//keyMinor indicates the actual letter currently assumed
	//only useful when keyMajor > -1, therefore keyMinor is not initialised
	//if keyMajor > -1, then keyMajor value refers to a string in keys, while keyMinor refers to a letter within that string
	int keyMinor;
        
        /**
         * to control long pressing down or up key
         */
        static private Timer scrollTimer;
        /**
         * used in combination with scrollTimer, if true then scrolling up, otherwise scrolling down
         */
        private boolean scrollingUp;
        
        /**
         * used in combination with scrollTimer, is the delay to use in next scrolltimer
         */
        private int scrollDelay;
        
        /**
         * used in combination with scrollTimer, first scroll delay in ms
         */
        static private int firstScrollDelay = 500;
        /**
         * used in combination with scrollTimer, secondt scroll delay in ms
         */
        static private int secondScrollDelay = 250;

	//keyMajor is used to indicate if the system is waiting for a timer expiry or not
	//keyMajor > -1 should mean a timer is still running (otherwise there's a bug)
	//keyMajor > -1 means user pressed a valid key a while ago but might press the same key again, resulting in another letter on the same key
	//if keyMajor > -1 then it corresponds to teh value of the previous key pressed taking into account the offset. Ie if user pressed Key 2
	// then keyMajor getsvalue 0, because 2 is the key that contains the letters "abc" which is in key[0]
	// keymajor and keyMinor will be used by methods replaceCharInText and addCharInText to determine the value of the character to add


        //the textbox and cmdlistner  will be used to let the user confirm deletion of item list
        private Alert confirm;
        private CommandListener cmdlistner;

        // constructor class for GetItemFromUser
        // parameter userfont is used to let the user decide which font he wants to use
        // it's mainly to allow the user to decide on the size.'
        //
        // parameter midlet is passed and will be passed further on to other classes
        // this allows me to change displayables
	public GetItemFromUser(Font userfont, HelpDiabetes midlet) {
                super(userfont,midlet);
                additem = new AddItem(userfont,midlet);
                ritmlist = new ReadItemList(userfont,midlet);
                deepsearch = new DeepSearch(userfont,midlet);

                be = new byte[maxblength];


                //the commands
                exit = new Command(str_afsl_short[HelpDiabetes.languageIndex],str_afsl[HelpDiabetes.languageIndex],Command.EXIT,1);
                this.addCommand(exit);
                kiezen = new Command(str_kiezen[HelpDiabetes.languageIndex],Command.SCREEN,3);
                this.addCommand(kiezen);
                showlist = new Command(str_lijst[HelpDiabetes.languageIndex],str_tnlijst[HelpDiabetes.languageIndex],Command.SCREEN,3);
                this.addCommand(showlist);
                empty = new Command (str_leegm[HelpDiabetes.languageIndex],str_leegml[HelpDiabetes.languageIndex],Command.SCREEN,3);
                this.addCommand(empty);
                deepsearch_cmd = new Command(str_deepsrch_short[HelpDiabetes.languageIndex],str_deepsrch[HelpDiabetes.languageIndex],Command.SCREEN,3);
                this.addCommand(deepsearch_cmd);

                loadfile = new Command(str_herl[HelpDiabetes.languageIndex],str_herll[HelpDiabetes.languageIndex],Command.SCREEN,3);
                this.addCommand(loadfile);
                settings = new Command(str_settings[HelpDiabetes.languageIndex],Command.SCREEN,3);
                this.addCommand(settings);
                infopage = new Command(str_info[HelpDiabetes.languageIndex],Command.SCREEN,3);
                this.addCommand(infopage);
                this.setCommandListener(this);
       }

    protected void keyReleased(int keyCode) {
        cancelScrollTimer();
    }

	// If a numeric key is pressed, If you already have a timer running, you cancel it since a key was pressed (note that timer running
	// should also mean keyMajor > -1
	// Then, you subtract the code of the 2 key from the current key code in order to calculate the index in your key array.
	// (key 2 is the key that contains the first letters of the alphabet namely "abc")
	// If keyMajor > -1 and the key pressed is the same as the previous key pressed then it means
	// the user has pressed the same key within the predefined timelimit, so the next letter
	// on that key must be pointed to. The cursor in the textfield does not move but the last letter is
	// replaced by this subsequent letter in that string. When this happens we call replaceCharInText()
	// If keyMajor > -1 and the key pressed is not the same as the previous key pressed then it means
	// the user has pressed a new key, the textfield cursor needs to move, and a new letter is added in the textfield corresponding to
	// the first letter in string pointed to by the new value of the key. When this happens we call addCharInText()
        public synchronized void keyPressed (int keyCode) {

                resetexittimer();

                if (keyTimer != null)  keyTimer.cancel ();

                cancelflipfloptimer();
                cancelScrollTimer();

                //back and clear key same as left key
                if ( (getGameAction(keyCode) != RIGHT) && (getGameAction(keyCode) != UP) && (getGameAction(keyCode) != DOWN) && (getGameAction(keyCode) != FIRE)) {
                        if ((keyCode ==  BACK_KEY) || (keyCode == CLEAR_KEY)) {
                            keyCode = getKeyCode(LEFT);
                        }
                }

                if ((keyCode == KEY_POUND) ||  (keyCode == KEY_STAR))  {// space needs to be entered
                    //note added 20/11 : on my Motorola razr V9 this doesn't work, I assume because my Mot returns keyCode = 32 which is ' ' in stead of keyPound'
                    // doesn't matter if application was waiting for the keyConfirmed timer or not
                    // I'll add a blank and move the cursor
                    addCharInText(' ');
                    keyMajor = -1;
                    // = true;
                    repaint();
                    synchronized (enteredstring) {
                        enteredstring.notify();
                    }
                    resetflipfloptimer(this);
                }  else  //check if it's a character, either in full keyboard, normal keyboard or blackberry pearl'
                    if ( (        (keyCode > (KEY_NUM0 - 1)) && (keyCode < (KEY_NUM9 +1))      )     //it's a digit that was pressed, on a normal keyboard'
                           ||
                         (        (64 < keyCode)            &&  (keyCode < 91)                 )
                           ||
                         (        (96 < keyCode)             && (keyCode < 123)                )   )
                    {
                            int index = keyCode - KEY_NUM2; // Key 2 contains the first set of letters of the alphabet ie "abc" or something else in case of blackberry
                          if (index < 0 || index > keys.length) {// a non-numeric key was pressed (in case of bb : a key was pressed that doesn't contain characters, for instance delete or space' although we shouldn't have reached this I guess if it was space or delete'
                                //first check if it's a character a-z or A-Z, this could be the case with devices that have a full keyboard like Nokia E61
                                if ( ((64 < keyCode) & (keyCode < 91)) ||  ((96 < keyCode) & (keyCode < 123)) ) {
                                    //here I'm doing something tricky
                                    //since I'm getting an ascii code of a real character, this is being used by a device that has a complete keyboard, not with a normal gsm keyboard with 3 characters on one button
                                    //So, as soon as the character is added, the sorting needs to start, there's no need to wait for a keyconfirmation
                                    addCharInText(Character.toLowerCase((char)keyCode));
                                    //repaintcompletely=true;
                                    repaint();
                                }

                                // following comment and statement keyMajor = -1 is only relevant for normal devices where keycode is a numeric value
                                // a non-numeric key is pressed, we don't care of it's been repeated within the limit or not
                                // if keyMajor = -1 then it means the keyconfirmer timer was not running
                                // if keyMajor > -1 keyConfirmer was running, and pressing this non valid key also confirms the key
                                // so in any case I'm setting keyMajor back to -1
                                keyMajor = -1;

                                // the flipfloptimer needs to be restarted
                                resetflipfloptimer(this);
                             }  else { // a key containing letters was pressed - 20/11 : what I actually mean is it was key 2, 3, 4, 5, 6, 7 , 8 or 9, these keys contains letters on normal phones
                                    if (index != keyMajor) {//for sure it's a new key pressed, so I have to add it
                                            keyMinor = 0;
                                            keyMajor = index;
                                            showCursor = false;// we don't want to show the cursor has along as the 500 ms hasn't expired, during which
                                                               // user can press same key to get another letter on the same key'
                                            addCharInText(keys[keyMajor].charAt(keyMinor));
																						//there's no need to repaint the complete screen because no new search is happening yet
                                            repaint();
                                    }
                                    else {//index = keyMajor, which means keyMajor > -1, which means the timer was still running at the moment the key was pressed
                                            //so we keep the cursor but replace the last character in the textfield by the next character in the string corresponding to this key
                                            keyMinor++;
                                            showCursor = false;// we don't want to show the cursor has along as the 500 ms hasn't expired, during which
                                                               // user can press same key to get another letter on the same key'
                                            if (keyMinor >= keys[keyMajor].length ())
                                                    keyMinor = 0;
                                            replacecharInText(keys[keyMajor].charAt(keyMinor));
																						//there's no need to repaint the complete screen because no new search is happening yet
                                            repaint();
                                    }

                                    keyTimer = new Timer ();
                                    keyTimer.schedule(new KeyConfirmer (this), 500);
                            }
                        } else if (getGameAction (keyCode) == LEFT ) {
                              if (enteredstring.enteredstringlength > 0) {
                                    synchronized (enteredstring) {
                                        enteredstring.enteredstring[enteredstring.enteredstringlength] = '0';
                                        enteredstring.enteredstringlength--;
                                        enteredstring.notify();
                                       }
                               }
                        } else if (getGameAction (keyCode) == RIGHT) {
                            //switch to it itemlist
                            ritmlist.showlist();
                        } else if (getGameAction (keyCode) == UP) {
                            scrollUp();
                            resetScrollTimer(firstScrollDelay);
                        } else if (getGameAction (keyCode) == DOWN) {
                            scrollDown();
                            resetScrollTimer(firstScrollDelay);
                        } else if (getGameAction (keyCode) == FIRE) {
                            additem.ItemSelected(shownrec,true,"0.0",0,1);
                        }
                        //if ( (getGameAction (keyCode) == UP) || (getGameAction (keyCode) == DOWN) || (getGameAction (keyCode) == LEFT) || (getGameAction (keyCode) == RIGHT)) {
                        flipflopthecursor();
                        //}

	}

	// this is called when keyconfirmed timer expires, via KeyConfirmer
	synchronized void keyConfirmed () {
                keyTimer = null;
		keyMajor = -1; // next time a key is pressed it will be interpreted as a new key
                resetflipfloptimer(this);
	}
        
        private void resetScrollTimer(int delay) {
            cancelScrollTimer();
            scrollTimer = new Timer();
            scrollTimer.schedule(new ScrollTimerTask(this),delay);
        }

        private void scrollUp() {
            if (shownrec > (FoodFile.nrofrecstoskip + 1)) {
                shownrec--;
                repaint();
                scrollingUp = true;
            }
        }

        private void scrollDown() {
            if (shownrec < foodrssize) {
                shownrec++;
                repaint();
                scrollingUp = false;
            }
        }
        
        public void makeFirstScroll() {
            if (scrollingUp) {
                if (shownrec > (FoodFile.nrofrecstoskip + 1)) {
                    shownrec--;
                    repaint();
                    resetScrollTimer(secondScrollDelay);
                } 
            } else {
                if (shownrec < foodrssize) {
                    shownrec++;
                    repaint();
                    resetScrollTimer(secondScrollDelay);
                }
            }
        }

        private void cancelScrollTimer() {
            if (scrollTimer != null) {
                scrollTimer.cancel();
                scrollTimer = null;
            }
        }

            public void paint (Graphics graphics) { // abstract method in Canvas which needs to be overloaded
                int i;
		x=0;y=0;
                //first set the font to the one passed to the constructor of GetItemFromUser
                graphics.setFont(userfont);

                //clear the screen - can be better - not necessary to clear the complete screen
                graphics.setColor(255,255,255);
                graphics.fillRect(0, 0, scrwidth, scrhght);

                //print active insulin
                float amountToShow = ActiveInsulinManagement.getTotalActiveInsulin();
                float multiplywith10 = amountToShow * (float) 10;
                float Plus0Dot5 = multiplywith10 + (float) 0.5;
                int toInt = (int)Plus0Dot5;
                float DivideBy10 = ((float)toInt) / (float)10;
                paintstring(("IOB" + " = " + DivideBy10).getBytes(),false,graphics,userfont);
                x=0;y= y+fonthght;
                //a horizontal line
                graphics.drawLine(0,y,scrwidth,y);
                
                /** Prints 'Zoek : ' **/
                paintstring((str_zoek[HelpDiabetes.languageIndex] + " : ").getBytes(),false,graphics,userfont);
                /** the current contents of the searchstring */
                paintstring( (new String(enteredstring.enteredstring,0,enteredstring.enteredstringlength)).getBytes(),false,graphics,userfont);

                //print the cursor
                printcursor(graphics, false);
                // go to next line
                x=0;y= y+fonthght;

                // a horizontal line under the enteredstring
                graphics.drawLine(0,y,scrwidth,y);
                y=y+1;

                try {
                    if (HelpDiabetes.foodrs != null) {
                        if (shownrec > 0) {
                           //first show first rec inverted - don't care if it fits on screen or not, normally it should'
                            paintstring(b,blength = FoodFile.getRecord(shownrec,b,0),true,graphics,userfont);
                            graphics.setColor(0,0,0);
                            graphics.fillRect(x,y,scrwidth-x,fonthght);
                            graphics.setColor(255,255,255);

                            x=0;y=y+fonthght;
                            i = shownrec+1;
                            while ((i < (foodrssize + 1))) {
                                paintstring(b,blength = FoodFile.getRecord(i,b,0),false,graphics,userfont);
                                if (!(y + fonthght < scrhght)) {
                                    i = foodrssize;//this will stop the printing
                                } else {
                                    y = y + fonthght;x = 0;
                                }
                                i++;
                            }
                        }
                    }
                } catch (InvalidRecordIDException ex) {
                    ;
                } catch (RecordStoreNotOpenException ex) {
                    ;
                } catch (RecordStoreException ex) {
                    ;
                }
        }

    private void addCharInText(char c) {
        // will add char in the string
        // if maximum length already reached then nothing is added
        if (enteredstring.enteredstringlength < enteredstring.maxenteredstringlength) {
            synchronized (enteredstring) {
                enteredstring.enteredstring[enteredstring.enteredstringlength] = c;
                enteredstring.enteredstringlength++; // the actual number of letters already in the array
                enteredstring.notify();
            }
       }
    }

    private void replacecharInText(char c) {
        synchronized (enteredstring) {
            enteredstring.enteredstring[enteredstring.enteredstringlength-1] = c;
            enteredstring.notify();
        }
       }

    public void run() {
      try {
        //this method will continuously run and do the searching of the string in the recordstore

        //holds per possible index the value of firstline and lastline
        //this is used for when user has pressed backspace, in that case no reasearch is necessary but stored values can be used
        int frstline[] = new int[SearchString.maxenteredstringlength+2];//to avoid ArrayIndexOutOfBoundsException
        int lastline[] = new int[SearchString.maxenteredstringlength+2];//to avoid ArrayIndexOutOfBoundsException

        // will hold the string searched so far.
        char[] copyofsrchstr =  new char[SearchString.maxenteredstringlength+2];//to avoid ArrayIndexOutOfBoundsException

        //The record id of the first item. Index 0 if firstline arry corresponds to the case where no characters are entered in the enteredstring. So firstline[0] should be set to FoodFile.nrofrecstoskip + 1;
        frstline[0] = FoodFile.nrofrecstoskip + 1;
        //The record id of the last item.
        lastline[0] = foodrssize;
        firstrec = frstline[0];
        lastrec = lastline[0];
        boolean search = false;//indicates if search is necessary
        int index = 0;//will point to the index of the character in the enteredstring array
        char comp = '\0';//will get the value of the char in the enteredstring that needs to be searched for
        int inline;

        while(1 > 0) {// this is an endless loop
            while (!search) {
                //for each character in the copyofsrchstr, we'll compare to the actual enteredstring
                //as of the first difference, we now we need to start searching
                //we'll start looking for a difference between copyofsrchstr and enteredstring
                index = -1;
                synchronized (enteredstring) {// i don't want the other thread to change anything to enteredstring while I'm comparing values'
                    while ((index < (enteredstring.enteredstringlength-1)) & !search) {
                        index++;//here index points to the character in the enteredstring, so if eg = 0, means compare the first character
                        comp = enteredstring.enteredstring[index];
                        if (copyofsrchstr[index] != comp) {
                            //it means we found a different character
                            search = true;
                            copyofsrchstr[index+1] = 0;//this to avoid that there's still some data in there which was entered during a previous other enteredstring entry'
                        }
                    }
                    if (!search) {
                        //index + 1 is pointing to the records that should be shown
                        //first of all, let's make sure that paint will use the correct values because maybe user has entered the back-key'
                        firstrec = frstline[index+1];
                        lastrec = lastline[index+1];
                        shownrec = firstrec;
                        repaint();
                        //now wait
                        enteredstring.wait();
                    }
                }
            }
            //we got of the previous loop, so search is necessary
            //first of all we set search back to false, so we don't forget
            search = false;
            copyofsrchstr[index] = comp;

            if ((inline = Searchfirst(frstline[index],lastline[index],charorder[comp],index)) > 0) {
                frstline[index+1] = inline;
                // no need to check if inline > 0 we should find something or there's something terribly wrong because we found a firstline'
                // working with frstline[index + 1] because there's no need to research as of previous first line
                inline = Searchlast(frstline[index+1],newlast,charorder[comp],index);
                lastline[index+1] = inline;
            } else {
                 //we haven't found anything'
                 frstline[index+1] = frstline[index];
                 lastline[index+1] = lastline[index];
            }
        } // end of endless loop
      } catch (InterruptedException e) {
          (new ReportException()).Report("Exception in getitemfromuser.run()",e,true);
      }
    }

    // search the first line that has a matching value
    // low and high indicate first and last record
    // value is the char value according to charorder
    // index is the index of the byte to compare in the byte arrays stored in the records
    // return value is the id of the item - ie nrofrectoskip needs to be added
    // return -1 means not found
    //
    int Searchfirst (int low, int high, int value, int index) {
        int temp = 0;
        int temp2 = 0;
        int mid = 0;
        int returnvalue = -1;
        newlast = high;//will be set to lowest value where a character was found with value > value - will then be used by run() when calling searchlast to reduce searching time
        try {
           temp = high + 1;//this becomes the highest start value
           while (low < temp) {
               mid = (low + temp)/2;
               if (mid < 4) {
                   mid = mid;
               }
               belength = FoodFile.getRecord(mid,be,0);
               if (!(belength > index))//b is a string which is shorter than the enteredstring, so definitely before the enteredstring (smaller than)
                    {low = mid+1;}
               else {
                   if ((temp2 = charorder[0xFF & be[index]]) < value)
                       low = mid + 1;
                   else {
                       if (temp2 > value) {
                           newlast = mid;
                   }
                       temp = mid;
                   }
               }

           }

           if (low > high) {
               ;//returnvalue = -1;
           } else {
               belength = FoodFile.getRecord(low,be,0);
               if (belength > index) {
                   if ((low < (high + 1)) & (charorder[0xFF & be[index]] == value))
                           returnvalue = low;
               } else {
                   ;//returnvalue = -1;
               }
           }
        }  catch (Exception e)     {
            String toprint = new String(be);
            (new ReportException()).Report("Exception in Searchfirst\nlow = " + low
                    + "\nbe = " + toprint + "\nindex = " + index + "" +
                    "\nhigh= " + high + "\ntemp = " + temp + "\nmid = " + mid,e,false);
        } finally {
            return returnvalue;//doing this because otherwise i get a compile error. Noramally return should have happened already so this statement will never be executed
        }
    }

    // search the last line that has a matching value
    // low and high indicate first and last record
    // value is the char value according to charorder
    // index is the index of the byte to compare in the byte arrays stored in the records
    // return value is the id of the item - ie nrofrectoskip needs to be added
    // return -1 means not found
    //
    int Searchlast (int low, int high, int value, int index) {
        int temp = 0;
        int mid = 0;
        int returnvalue = -1;
        try {
           temp = low -1;
           while (high > temp) {
               if ((high + temp)%2 > 0) {mid = (high+temp)/2+1;}
               else {mid = (high+temp)/2;}
               belength = FoodFile.getRecord(mid,be,0);
               if (!(belength > index))//be is a string which is shorter than the enteredstring, so definitely before the enteredstring (smaller than)
                   {temp = mid;}
               else {
                   if (charorder[0xFF & be[index]] > value)
                       high = mid - 1;
                   else
                        //can't be high = mid-1: here A[mid] >= value,
                        //so high can't be < mid if A[mid] == value
                        temp = mid;
               }

           }
           if (high < low) {
               ;//returnvalue = -1;
           } else {
               belength = FoodFile.getRecord(high,be,0);
               if (belength>index) {
                   if (((low-1) < high) & (charorder[0xFF & be[index]] == value))
                       returnvalue = high;
               } else {
                   ;//returnvalue = -1;
               }
           }
       }  catch (Exception e)     {
            (new ReportException()).Report("Exception in Searchlast\nlow = " + low
                    + "\nhigh= " + high + "\ntemp = " + temp + "\nmid = " + mid
                    + "\nindex = " + index + "\nvalue = " + value,e,true);
        } finally {
            return returnvalue;//doing this because otherwise i get a compile error. Noramally return should have happened already so this statement will never be executed
        }
    }



    public void commandAction(Command command, Displayable displayable) {
        resetexittimer();
        String temp_string;
        String foodtablesource = null;

        if (command == exit) {
            midlet.exitMIDlet();
        }  else if (command == deepsearch_cmd) {
            if (deepsearch == null) {
                deepsearch = new DeepSearch(userfont,midlet);
            }
            deepsearch.search();
        }  else if (command == empty) {
            try {
                // try to open the recordstore, if it's not existing an error will be thrown and caught, this means it's not existing'
                RecordStore.openRecordStore("selecteditems",false).closeRecordStore();
                curdisp = HelpDiabetes.midlet.getDisplay().getCurrent();
                if (confirm == null) {
                    confirm = new Alert(null,str_confirm[HelpDiabetes.languageIndex],null,AlertType.WARNING);
                    confirm.setTimeout(Alert.FOREVER);
                    ja = new Command(str_ja[HelpDiabetes.languageIndex],Command.OK,0);
                    nee = new Command(str_nee[HelpDiabetes.languageIndex],Command.BACK,0);
                    confirm.addCommand(ja);
                    confirm.addCommand(nee);
                    cmdlistner = new CommandListener() {
                        public void commandAction(Command command, Displayable displayable) {
                            if ((command == ja) | (command == Alert.DISMISS_COMMAND)) {
                                try {HelpDiabetes.closeSelectedItemsRs();} catch (Exception ex) {;}
                                try {RecordStore.deleteRecordStore("selecteditems");} catch (Exception ex) {;}
                                HelpDiabetes.setSelectedItemsRsToNull();
                            }
                            HelpDiabetes.midlet.getDisplay().setCurrent(curdisp);
                        }
                    };
                }
                confirm.setCommandListener(cmdlistner);
                HelpDiabetes.midlet.getDisplay().setCurrent(confirm);
            }
            catch (RecordStoreNotFoundException ex) {//recordstore not existing, not necessary to do anything
                (new UserInfo()).Report(str_lijstleeg[HelpDiabetes.languageIndex]);
            } catch (Exception ex) {
                (new ReportException()).Report("Exception in getitemfromuser.commandAction, command = empty",ex,true);
            }
        }
        else if (command == loadfile) {//new file to be loaded
             new Thread(new Runnable() {
                    public void run() {
                        HelpDiabetes.foodfileinst.showCurrDir();
                    }
             }).start();

        }
        else if (command == showlist) {// list in selitemsrs to be shown
            ritmlist.showlist();
        } else if (command == settings) {//user wants to change the settings
            if (changesettingsform == null) {
                changesettingsform = new ChangeSettingsForm(HelpDiabetes.midlet.getDisplay().getCurrent());
            }
            HelpDiabetes.midlet.getDisplay().setCurrent(changesettingsform);
        }
        else if (command == kiezen) {
            additem.ItemSelected(shownrec,true,"0.0",0,1);
        } else if (command == infopage) {
                    temp_string = 
                    "HelpDiabetes\n" +  "\n" +
                    InitialScreen.str_startmessage1[HelpDiabetes.languageIndex].replace('|', ',') + "\n" + "\n" +
                    InitialScreen.str_startmessage2[HelpDiabetes.languageIndex].replace('|', ',') + 
                    InitialScreen.str_startmessage3[HelpDiabetes.languageIndex].replace('|', ',') + "\n" +
                    InitialScreen.str_startmessage4[HelpDiabetes.languageIndex].replace('|', ',') + "\n" +
                    InitialScreen.str_startmessage5[HelpDiabetes.languageIndex].replace('|', ',') + "\n" +
                    InitialScreen.str_startmessage6[HelpDiabetes.languageIndex].replace('|', ',');

                (new UserInfo()).Report(temp_string);
            }
    }

      public void emptyenteredstring() {
         if (enteredstring.enteredstringlength > 0) {
             synchronized (enteredstring) {
                  while (enteredstring.enteredstringlength > 0) {
                            enteredstring.enteredstring[enteredstring.enteredstringlength] = '0';
                            enteredstring.enteredstringlength--;
                           }
                      enteredstring.notify();

                   }
             return;
         } else return;
    }

    String GetClassName() {
        return("GetItemFromUser");
    }

//changed completely on 18/09/2009 to support selecting any element from the list
    protected void pointerPressed(int x, int y) {
        //first call super.pointerpressed, to check if a virtual keyboard is used
        super.pointerPressed(x, y);
    }
}